/*  

Cafechess Library: Cover basic chess programming needs, like GUI, Engine integration, 
FEN and PGN parsing.

                 \\|//
                 (o o)
--------------ooO-(_)-Ooo----------------------------------
Copyright (C) 2009  By Gregory A. Prentice Snoqualmie, WA
                    www.cafechess.org
                    cafechess@comcast.net
                      Oooo
--------------oooO----(  )---------------------------------
              (  )    (_/
               \_)

Microsoft Public License (Ms-PL)
               
Revisions:

Author        Date    Description:

*/
using System;
using System.Drawing;
using System.Collections;
using Cafechess.Imaging;

namespace Cafechess.Chess.Controls
{
	/// <summary>
	/// The layer that is responsible for drawing our squares of the chessboard.
	/// </summary>
  public class BoardLayer: Layer
  {
    #region Fields
    Bitmap coWhiteSquare;
    Bitmap coBlackSquare;
    //Bitmap coColorWhite;
    //Bitmap coColorBlack;
    /// <summary>
    /// Used to ensure we clean up our temporary square color.
    /// </summary>
    BitArray coLastSquareArray;
    #endregion Fields

    #region Properties
    public Bitmap WhiteSquare
    {
      get{ return coWhiteSquare; }
      set{ coWhiteSquare=value; }
    }
    public Bitmap BlackSquare
    {
      get{ return coBlackSquare; }
      set{ coBlackSquare = value; }
    } 
    public override Rectangle Square
    {
      get
      {
        return base.Square;
      }
      set
      {
        base.Square = value;
        //GenerateBoard();
      }
    }
    /// <summary>
    /// See IChessboardGui
    /// </summary>
    public Color WhiteColor
    {
      get{return coWhiteSquare.GetPixel(1,1);}      
    }
    /// <summary>
    /// See IChessboardGui
    /// </summary>
    public Color BlackColor
    {
      get{return coBlackSquare.GetPixel(1,1);}      
    }

    public BitArray LastHighlights
    {
      get{ return coLastSquareArray; }
    }

    #endregion Properties

    #region Constructors
    /// <summary>
    /// Construct our surface object that will manage the physical drawing bitmap
    /// and the order in which our layers are applied to the image.
    /// </summary>
    /// <param name="rectangle"></param>
    public BoardLayer(Rectangle rectangle, Color background) : base(rectangle,background)
    {
      SquareImageList il = new SquareImageList(Color.BlanchedAlmond,Color.BurlyWood,new Size(50,50));
      WhiteSquare = il.SquareImages.Images[0] as Bitmap;
      BlackSquare = il.SquareImages.Images[1] as Bitmap;
      il.Dispose();
      il=null;
      Color [] weakSquares = new Color[5];
      weakSquares[0] = Color.Red;
      weakSquares[1] = Color.Orange;
      weakSquares[2] = Color.Yellow;
      weakSquares[3] = Color.Blue;
      weakSquares[4] = Color.Green;
      WeakSquares = weakSquares;
    }
    #endregion Constructors

    /// <summary>
    /// This method gets called form an event that gets fired by the ChessSurface class
    /// which manages the creation of our chess board squares and their locations.
    /// </summary>
    /// <param name="ps"></param>
    /// <param name="create"></param>
    public void SquareGenerated(PieceSquare ps, bool create)
    {
      DrawableBitmap db;
      if( create )
      {
        db = new DrawableBitmap(ps.Name);
        db.IsEnabled = true;
        Add(db);
      }
      else
      {
        db = Get(ps.Index) as DrawableBitmap;
      }
      db.Square = ps.Square;
      db.Drawing = ps.Color ? coWhiteSquare : coBlackSquare; 
    }
    /// <summary>
    /// Used to change the color of the squares used to display our board.
    /// </summary>
    /// <param name="white"></param>
    /// <param name="black"></param>
    public void ColorSquares(System.Drawing.Color white, System.Drawing.Color black)
    {
      Bitmap ColorWhite=null, ColorBlack=null;
      SquareImageList il = new SquareImageList(white,black,new Size(50,50));
      ColorWhite = il.SquareImages.Images[0] as Bitmap;
      ColorBlack = il.SquareImages.Images[1] as Bitmap;
      il.Dispose();
      il=null;
      ColorSquares(ColorWhite,ColorBlack);
    }

    /// <summary>
    /// Used to set a specific user defined bitmap for use with the board squares.
    /// </summary>
    /// <param name="colorWhite"></param>
    /// <param name="colorBlack"></param>
    public void ColorSquares(Bitmap colorWhite, Bitmap colorBlack)
    {
      PieceSquare ps;
      ChessSurface cs = (ChessSurface)Parent;
      for(int ndx=0; ndx <64; ndx++)
      {
        ps = cs.FindPiece(ndx);
        DrawableBitmap db = (DrawableBitmap) Get(ps.Index);
        db.Drawing = ps.Color ? colorWhite : colorBlack; 
      }
      lock(this)
      {
        DisposeSquares();
        coWhiteSquare = colorWhite;
        coBlackSquare = colorBlack;
      }
      IsRedraw = true;
      Parent.IsRedraw = true;
    }
    /// <summary>
    /// Responsible for adding another square color pattern to the existing board schema.
    /// this is normally used to show things like the square a piece attacks.
    /// </summary>
    /// <param name="squareArray"></param>
    /// <param name="color">Color used to paint square, if Color.Transparent then change back to original color</param>
    public void AlternateColorSquares(BitArray squareArray, int[] intensity, System.Drawing.Color color)
    {
      if( squareArray != null && squareArray.Length >= 64 )
      {
        SquareImageList il = null;
        Bitmap colorWhite=null, colorBlack=null;
        // Always clear the previous opperation if one occured.
        if(coLastSquareArray != null )
        {
          BitArray temp = coLastSquareArray;
          coLastSquareArray = null;
          // Recursive call to clear our last color.
          AlternateColorSquares(temp,null,Color.Transparent);
        }
        if(Color.Transparent != color)
        {
          il = new SquareImageList(color,new Size(50,50),Color.Black ); //SquareImageList(color,new Size(50,50));
          colorWhite =(Bitmap) il.SquareImages.Images[0];
          colorBlack = (Bitmap) il.SquareImages.Images[1];
          il.Dispose();
        }
        ChessSurface cs = (ChessSurface)Parent;
        ulong mask = Cafechess.Chess.Validation.BitboardSquare.MaskHighBit;
        // Main loop for painting the squares.
        for(int ndx = 63; ndx >= 0; ndx--)
        {
          if(squareArray.Get(ndx))
          {
            string notation = Cafechess.Chess.Validation.BitboardSquare.SquareToAlpha(ndx);
            PieceSquare ps = cs.FindPiece(notation);
            DrawableBitmap db = (DrawableBitmap) Get(ps.Index);            
            if (Color.Transparent == color)
            {
              // Putting the board back to normal highlights.
              db.Drawing = ps.Color ? coWhiteSquare : coBlackSquare;
            }
            else if (intensity != null)
            {
              // Don't go over the length of our array.
              int i = Math.Min( Math.Abs(intensity[ndx]), WeakLightSquare.Length);
              i--;
              db.Drawing = ps.Color ? WeakLightSquare[i]: WeakDarkSquare[i];
            }
            else
            {
              db.Drawing = ps.Color ? colorWhite : colorBlack;
            }
            db.IsRedraw = true;
          }        
          mask = mask >> 1;
        }

        lock(this)
        {
// May not need this
//          DisposeColorSquares();
          if(Color.Transparent != color)
          {
// May not need this.
//            coColorWhite = colorWhite;
//            coColorBlack = colorBlack;
            coLastSquareArray = squareArray.Clone() as BitArray;
          }
          else
          {
            coLastSquareArray = null;
          }
          IsRedraw = true;
          Parent.IsRedraw = true;
        }
      }
    }

    private Bitmap[] WeakLightSquare
    {
      get;
      set;
    }
    private Bitmap[] WeakDarkSquare
    {
      get;
      set;
    }

    public Color[] WeakSquares
    {
      set
      {
        DisposeWeakSquares();
        if(value != null && value.Length > 0 )
        {
          WeakLightSquare = new Bitmap[value.Length];
          WeakDarkSquare = new Bitmap[value.Length];

          for (int ndx = 0; ndx < value.Length; ndx++)
          {
            SquareImageList il = new SquareImageList(value[ndx], new Size(50, 50), Color.Black);
            WeakLightSquare[ndx] = (Bitmap)il.SquareImages.Images[0];
            WeakDarkSquare[ndx] = (Bitmap)il.SquareImages.Images[1];
            il.Dispose();
          }
        }
      }
    }

    override protected void DisposeManaged()
    {
      base.DisposeManaged();
      if( ! IsDisposed )
      {
      }
    }
    override protected void DisposeUnmanaged()
    {
      base.DisposeUnmanaged();
      if( ! IsDisposed )
      {
        DisposeSquares();
        //DisposeColorSquares();
        DisposeWeakSquares();
      }
    }

    private void DisposeWeakSquares()
    {
      if (WeakLightSquare != null)
      {
        foreach (Bitmap bm in WeakLightSquare)
        {
          bm.Dispose();
        }
        WeakLightSquare = null;
      }
      
      if (WeakDarkSquare != null)
      {
        foreach (Bitmap bm in WeakDarkSquare)
        {
          bm.Dispose();
        }
        WeakDarkSquare = null;
      }

    }

    //private void DisposeColorSquares()
    //{
    //  if( coColorWhite != null )
    //  {
    //    coColorWhite.Dispose();
    //    coColorWhite = null;
    //  }       
    //  if( coColorBlack != null )
    //  {
    //    coColorBlack.Dispose();
    //    coColorBlack = null;
    //  }
    //}

    private void DisposeSquares()
    {
      if( coWhiteSquare != null )
      {
        coWhiteSquare.Dispose();
        coWhiteSquare = null;
      }       
      if( coBlackSquare != null )
      {
        coBlackSquare .Dispose();
        coBlackSquare  = null;
      }
    }

	}
}
